﻿using System;
using System.Collections.Generic;
using TSU.FAMC.ComputerEngineering.Classes.Circuits.Events;
using TSU.FAMC.ComputerEngineering.Classes.Enums;

namespace TSU.FAMC.ComputerEngineering.Classes.Circuits
{
    /// <summary>
    /// Delegate for CircuitInterface events.
    /// </summary>
    /// <param name="sender">Sender object.</param>
    /// <param name="e">Event arguments.</param>
    public delegate void CircuitInterfaceEventHandler(object sender, CircuitInterfaceEventArgs e);

    /// <summary>
    /// Represents a circuit interface for inputs/outputs.
    /// </summary>
    public class CircuitInterface : List<Circuit>
    {
        // Events

        /// <summary>
        /// Fires when the interface has been modified.
        /// </summary>
        public event CircuitInterfaceEventHandler OnModified;

        /// <summary>
        /// Fires when the interface is about to be modified.
        /// </summary>
        public event CircuitInterfaceEventHandler OnPreModified;
        
        // Methods

        /// <summary>
        /// Default contrucor.
        /// </summary>
        public CircuitInterface()
        {
        }

        /// <summary>
        /// Copy constructor.
        /// </summary>
        /// <param name="circuitInterface">CircuitInterface to copy values from.</param>
        public CircuitInterface(IEnumerable<Circuit> circuitInterface)
        {
            foreach (var pin in circuitInterface)
            {
                Add(pin);
            }
        }

        /// <summary>
        /// Fires OnModified event.
        /// </summary>
        public void FireOnModified(CircuitInterfaceEventArgs e)
        {
            if (ReferenceEquals(OnModified, null))
            {
                return;
            }

            OnModified(this, e);
        }

        /// <summary>
        /// Fires OnPreModified event.
        /// </summary>
        private void FireOnPreModified(CircuitInterfaceEventArgs e)
        {
            if (ReferenceEquals(OnPreModified, null))
            {
                return;
            }

            OnPreModified(this, e);
        }

        /// <summary>
        /// Adds new circuit at the end of the interface.
        /// </summary>
        /// <param name="circuit">Circuit object to add into the interface.</param>
        public new void Add(Circuit circuit)
        {
            // creating event args
            var args = new CircuitInterfaceEventArgs {Initiator = circuit, Action = CircuitInterfaceAction.Add};

            // firing OnPreModified event
            FireOnPreModified(args);

            // parent call
            ((List<Circuit>)this).Add(circuit);

            // firing OnModified event
            FireOnModified(args);
        }

        /// <summary>
        /// Adds circuit into the interface at specified index.
        /// </summary>
        /// <param name="index">Index to insert circuit at.</param>
        /// <param name="circuit">Circuit to add into the interface.</param>
        public new void Insert(int index, Circuit circuit)
        {
            // creating event args
            var args = new CircuitInterfaceEventArgs { Initiator = circuit, Action = CircuitInterfaceAction.Add };

            // firing OnPreModified event
            FireOnPreModified(args);

            // parent call
            ((List<Circuit>)this).Insert(index, circuit);

            // firing OnModified event
            FireOnModified(args);
        }

        

        /// <summary>
        /// Removes first occurrence of specified circuit from interface.
        /// </summary>
        /// <param name="circuit">Circuit object to remove.</param>
        /// <returns>True if circuit has been found and removed.</returns>
        public new bool Remove(Circuit circuit)
        {
            // creating event args
            var args = new CircuitInterfaceEventArgs {Initiator = circuit, Action = CircuitInterfaceAction.Delete};

            // firing OnPreModified event
            FireOnPreModified(args);

            // parent call
            var result = ((List<Circuit>)this).Remove(circuit);

            // firing OnModified event
            FireOnModified(args);

            return result;
        }

        /// <summary>
        /// Removes circuit from interface by index.
        /// </summary>
        /// <param name="index">Circuit index to remove.</param>
        public new void RemoveAt(int index)
        {
            // creating event args
            var args = new CircuitInterfaceEventArgs {Action = CircuitInterfaceAction.Delete};

            // parent call
            try
            {
                var circuitToRemove = this[index];

                args.Initiator = circuitToRemove;

                // firing OnPreModified event
                FireOnPreModified(args);

                ((List<Circuit>)this).RemoveAt(index);
            }
            catch (ArgumentOutOfRangeException e)
            {
                throw new ArgumentOutOfRangeException("Invalid index of circuit in the interface", e);
            }

            // firing OnModified event
            FireOnModified(args);
        }

        /// <summary>
        /// Removes all circuits from the interface.
        /// </summary>
        public new void Clear()
        {
            // creating event args
            var args = new CircuitInterfaceEventArgs {Action = CircuitInterfaceAction.Clear};

            // firing OnPreModified event
            FireOnPreModified(args);

            // parent call
            ((List<Circuit>)this).Clear();

            // firing OnModified event
            FireOnModified(args);
        }
    }
}
